#include "LeagueLayer.h"
#include "LeagueManager.h"
#include "Team.h"
#include "ServiceProvider.h"
#include "ZStream.h"
#include "Utilities.h"
#include "League.h"

#include <iterator>

LeagueLayer::LeagueLayer(ServiceProvider* i_sp)
	: m_settings()
	, m_isEnded(false)
	, m_sp(i_sp)
{}

LeagueLayer::~LeagueLayer()
{
	Clear();
}

void LeagueLayer::Initialize(const LeagueLayerSettings &i_settings)
{
	Clear();

	assert(m_settings.leagueNames.size() == m_settings.numOfLeagues);

	m_settings = i_settings;

	for(size_t i = 0; i < m_settings.numOfLeagues; ++i)
	{	
		League* league = new League(m_sp);
		std::string leagueName = i_settings.leagueNames[i];
		league->Initialize(leagueName, m_settings.leagueSettings);
		m_leagues.push_back(league);
	}
}

void LeagueLayer::Update(const bool i_doNotPrompt)
{
	if (m_isEnded)
		return;

	for(LeagueVecIt it  = m_leagues.begin(); it != m_leagues.end(); ++it)
	{
		League& theLeague = *(*it);
		theLeague.Update(i_doNotPrompt);
	}
	
	//END OF ONLY THIS LAYER
	const size_t currentTurn = m_sp->GetLeagueMgr().GetCurrentTurn();
	const size_t maxTurns = MaxTurnsOfSeason();
	if (currentTurn == maxTurns - 1)
		m_isEnded = true;
}

void LeagueLayer::PromoteAndDemote(LeagueLayer* i_lowerLayer, const bool i_doNotPrompt, std::stringstream& o_message)
{
	const size_t demot = m_settings.numOfDemotioned;
	const size_t teamsDemForLeague = m_settings.leagueSettings.numDemoted;
	const size_t teamsProForLeague = i_lowerLayer->m_settings.leagueSettings.numPromoted;

	TeamVec tempDem, tempDem2;
	TeamVec tempPro, tempPro2;
	tempDem.reserve(demot);
	tempPro.reserve(demot);

	for (LeagueVecIt it = m_leagues.begin(); it != m_leagues.end(); ++it)
	{
		(*it)->RemoveFirstOrLastTeams(tempDem2, teamsDemForLeague, true);
		std::copy(tempDem2.begin(), tempDem2.end(), std::back_insert_iterator<TeamVec>(tempDem));
		
		if(!i_doNotPrompt)
		{
			o_message << "League " << (*it)->GetName() << std::endl;
			for(TeamVecCit tIt = tempDem2.begin(); tIt != tempDem2.end(); ++tIt)
				o_message <<"\tTeam demoted: " << (*tIt)->GetName() << std::endl;
			o_message << std::endl;
		}
		
		tempDem2.clear();
	}

	for (LeagueVecIt it = i_lowerLayer->m_leagues.begin(); it != i_lowerLayer->m_leagues.end(); ++it)
	{
		(*it)->RemoveFirstOrLastTeams(tempPro2, teamsProForLeague, false);
		std::copy(tempPro2.begin(), tempPro2.end(), std::back_insert_iterator<TeamVec>(tempPro));

		if(!i_doNotPrompt)
		{
			o_message << "League " << (*it)->GetName() << std::endl;
			for(TeamVecCit tIt = tempPro2.begin(); tIt != tempPro2.end(); ++tIt)
				o_message <<"\tTeam promoted: " << (*tIt)->GetName() << std::endl;
			o_message << std::endl;
		}
		
		tempPro2.clear();
	}

	// Insert PROMOTED teams splitted for every league of the layer
	for (LeagueVecIt it = m_leagues.begin(); it != m_leagues.end(); ++it)
	{
		for (size_t i = 0; i < teamsDemForLeague; ++i)
		{
			(*it)->GetTeams().push_back(tempPro.back());
			tempPro.pop_back();
		}
	}
	
	// Insert DEMOTED teams splitted for every league of the layer
	for (LeagueVecIt it = i_lowerLayer->m_leagues.begin(); it != i_lowerLayer->m_leagues.end(); ++it)
	{
		for (size_t i = 0; i < teamsProForLeague; ++i)
		{
			(*it)->GetTeams().push_back(tempDem.back());
			tempDem.pop_back();
		}
	}
}

void LeagueLayer::Clear()
{
	Utilities::DeepClear(m_leagues);

	m_settings = LeagueLayerSettings();
}

void LeagueLayer::EndSeasonUpdate(const bool i_bDoNotPrompt, std::stringstream& o_message)
{
	m_isEnded = false;

	for(LeagueVecIt it  = m_leagues.begin(); it != m_leagues.end(); ++it)
		(*it)->EndSeasonUpdate(i_bDoNotPrompt, o_message);
}

ZStream& LeagueLayerSettings::Serialize(ZStream& o_stream)
{
	o_stream.WriteOpenTag("LeagueLayer");

	o_stream.WriteAttribute("Visible", isVisible);
	o_stream.WriteAttribute("LeagueNum", numOfLeagues);

	for(size_t i = 0; i < numOfLeagues; ++i)
	{
		o_stream.WriteAttribute("Name", leagueNames[i]);
	}

	o_stream.WriteAttribute("NumOfDemotioned", numOfDemotioned);

	// league settings
	o_stream.WriteAttribute("NumOfTeams",leagueSettings.numOfTeams);
	o_stream.WriteAttribute("MinStartingTeamBdg", leagueSettings.minStartingTeamBdg);
	o_stream.WriteAttribute("DeltaStartingTeamBdg", leagueSettings.deltaStartingTeamBdg);
	o_stream.WriteAttribute("MinMatchBoxOffice", leagueSettings.minMatchBoxOffice);
	o_stream.WriteAttribute("DeltaMatchBoxOffice", leagueSettings.deltaMatchBoxOffice);
	o_stream.WriteAttribute("MinEndSeasonTeamBdg", leagueSettings.minEndSeasonTeamBdg);
	o_stream.WriteAttribute("DeltaEndSeasonTeamBdg", leagueSettings.deltaEndSeasonTeamBdg);

	o_stream.WriteCloseTag("LeagueLayer");

	return o_stream;
}

ZStream& LeagueLayerSettings::Deserialize(ZStream& i_stream)
{
	i_stream.SkipLine();

	i_stream.ReadAttribute(isVisible);
	i_stream.ReadAttribute(numOfLeagues);

	for(size_t i = 0; i < numOfLeagues; ++i)
	{
		std::string name;
		i_stream.ReadAttribute(name);
		leagueNames.push_back(name);
	}

	i_stream.ReadAttribute(numOfDemotioned);

	// league settings
	i_stream.ReadAttribute(leagueSettings.numOfTeams);
	i_stream.ReadAttribute(leagueSettings.minStartingTeamBdg);
	i_stream.ReadAttribute(leagueSettings.deltaStartingTeamBdg);
	i_stream.ReadAttribute(leagueSettings.minMatchBoxOffice);
	i_stream.ReadAttribute(leagueSettings.deltaMatchBoxOffice);
	i_stream.ReadAttribute(leagueSettings.minEndSeasonTeamBdg);
	i_stream.ReadAttribute(leagueSettings.deltaEndSeasonTeamBdg);
	leagueSettings.numDemoted = numOfDemotioned/numOfLeagues;
	leagueSettings.numPromoted = numOfPromoted/numOfLeagues;
	leagueSettings.layerIndex = layerIndex;

	i_stream.SkipLine();

	return i_stream;
}